package com.dcy.oa.service;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.dcy.common.base.service.DcyBaseService;
import com.dcy.common.enums.TaskTypeEnum;
import com.dcy.common.model.PageModel;
import com.dcy.common.model.PageResult;
import com.dcy.common.model.flowable.ActProcessInstance;
import com.dcy.common.service.ActCompleteTaskService;
import com.dcy.common.service.ActFlowableTaskService;
import com.dcy.common.service.ActUserService;
import com.dcy.common.utils.LoginUtil;
import com.dcy.oa.convert.LeaveConvert;
import com.dcy.oa.dao.LeaveDao;
import com.dcy.oa.enums.LeaveStatusEnum;
import com.dcy.oa.model.Leave;
import com.dcy.oa.vo.in.LeaveCreateInVO;
import com.dcy.oa.vo.in.LeaveMeSearchInVO;
import com.dcy.oa.vo.in.LeaveSearchInVO;
import com.dcy.oa.vo.in.LeaveUpdateInVO;
import com.dcy.oa.vo.out.LeaveListOutVO;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;

/**
 * <p>
 * 请假服务实现类
 * </p>
 *
 * @author dcy
 * @since 2021-06-11
 */
@RequiredArgsConstructor
@Service("leaveService")
public class LeaveService extends DcyBaseService implements ActCompleteTaskService {

    private final ActFlowableTaskService actFlowableTaskService;
    private final LeaveDao leaveDao;
    private final LeaveConvert leaveConvert = LeaveConvert.INSTANCE;
    private final ActUserService actUserService;

    /**
     * 获取表格数据
     *
     * @param leaveSearchInVO
     * @param pageModel
     * @return
     */
    public PageResult<LeaveListOutVO> pageListByEntity(LeaveSearchInVO leaveSearchInVO, PageModel pageModel) {
        return toPageResult(leaveDao.pageListByEntity(leaveConvert.toLeave(leaveSearchInVO), pageModel).convert(leaveConvert::toOut));
    }

    /**
     * 获取表格数据
     *
     * @param leaveMeSearchInVO
     * @param pageModel
     * @return
     */
    public PageResult<LeaveListOutVO> getMeLeavePageList(LeaveMeSearchInVO leaveMeSearchInVO, PageModel pageModel) {
        final Leave leave = leaveConvert.toLeave(leaveMeSearchInVO);
        leave.setUserId(LoginUtil.getUserId());
        return toPageResult(leaveDao.pageListByEntity(leave, pageModel).convert(leaveConvert::toOut));
    }

    /**
     * 保存请假申请
     *
     * @param leaveCreateInVO
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public Boolean saveLeave(LeaveCreateInVO leaveCreateInVO) {
        Leave leave = leaveConvert.toLeave(leaveCreateInVO);
        final String userId = LoginUtil.getUserId();
        leave.setUserId(userId);
        leave.setName(actUserService.getNickNameByUserId(userId));
        leave.setStatus(LeaveStatusEnum.NOT_STARTED.getCode());
        leave.setLeaveDate(new Date());
        // 获取一个新的id
        final String idStr = IdWorker.getIdStr();
        leave.setId(idStr);
        leave.setStatus(LeaveStatusEnum.HAVE_IN_HAND.getCode());
        // 启动流程 并且 完成首个任务
        final ActProcessInstance actProcessInstance = actFlowableTaskService.startProcessAndCompleteFirstTask(leave.getId(), TaskTypeEnum.LEAVE, LoginUtil.getUserId());
        // 业务表关联流程id
        leave.setProcessInstanceId(actProcessInstance.getProcessInstanceId());
        return leaveDao.save(leave);
    }

    /**
     * 重新提交
     *
     * @param leaveUpdateInVO
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public Boolean reSubmitLeave(LeaveUpdateInVO leaveUpdateInVO) {
        Leave leave = leaveConvert.toLeave(leaveUpdateInVO);
        leave.setStatus(LeaveStatusEnum.HAVE_IN_HAND.getCode());
        final boolean success = leaveDao.updateById(leave);
        // 拼装 业务key
        String businessKey = StrUtil.builder()
                .append(TaskTypeEnum.LEAVE.getBusinessType())
                .append(":")
                .append(leave.getId()).toString();
        actFlowableTaskService.restart(businessKey, LoginUtil.getUserId());
        return success;
    }

    /**
     * 提交
     *
     * @param leaveUpdateInVO
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public Boolean submit(LeaveUpdateInVO leaveUpdateInVO) {
        Leave leave = leaveConvert.toLeave(leaveUpdateInVO);
        leave.setLeaveDate(new Date());
        leave.setStatus(LeaveStatusEnum.HAVE_IN_HAND.getCode());
        // 启动流程 并且 完成首个任务
        final ActProcessInstance actProcessInstance = actFlowableTaskService.startProcessAndCompleteFirstTask(leave.getId(), TaskTypeEnum.LEAVE, LoginUtil.getUserId());
        // 业务表关联流程id
        leave.setProcessInstanceId(actProcessInstance.getProcessInstanceId());
        return leaveDao.updateById(leave);
    }

    @Override
    public void updateCompleteStatusById(String id) {
        Leave leave = new Leave();
        leave.setId(id);
        leave.setStatus(LeaveStatusEnum.COMPLETED.getCode());
        leaveDao.updateById(leave);
    }

    @Override
    public void updateRejectStatusById(String id) {
        Leave leave = new Leave();
        leave.setId(id);
        leave.setStatus(LeaveStatusEnum.REJECT.getCode());
        leaveDao.updateById(leave);
    }

    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteLeave(String id) {
        final Leave leave = leaveDao.getById(id);
        // 拼装 业务key
        String businessKey = StrUtil.builder()
                .append(TaskTypeEnum.LEAVE.getBusinessType())
                .append(":")
                .append(leave.getId()).toString();
        actFlowableTaskService.delete(businessKey);
        return leaveDao.removeById(id);
    }

    public LeaveListOutVO getLeaveById(String id) {
        return leaveConvert.toOut(leaveDao.getById(id));
    }

    public Boolean save(LeaveCreateInVO leaveCreateInVO) {
        Leave leave = leaveConvert.toLeave(leaveCreateInVO);
        final String userId = LoginUtil.getUserId();
        leave.setUserId(userId);
        leave.setName(actUserService.getNickNameByUserId(userId));
        leave.setStatus(LeaveStatusEnum.NOT_STARTED.getCode());
        leave.setLeaveDate(new Date());
        return null;
    }
}
